package com.xl.utils.file;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author:XueH
 * @Description:
 * @Date:Created in 14:42 2022/8/23
 * @Modified By:
 */
@Slf4j
@Data
public class FileUtil {

    //时间格式化标准
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    /**
     * 根据文件全路径判断文件是否存在
     *
     * @param path 全路径
     * @return
     */
    public static boolean exist(String path) {
        File file = getFile(path);
        return file.exists();
    }

    /**
     * 判断文件是否存在
     * 存在返回文件
     *
     * @param path 根据文件全路径判断文件是否存在
     * @return
     */
    public static File existRetFile(String path) {
        File file = getFile(path);
        if (file.exists()) {
            return file;
        }
        return null;
    }

    /**
     * 输入路径判断文件夹是否存在 不存在则进行创建
     *
     * @param path
     */
    public static void noExistCreateDir(String path) {
        File file = getFile(path);
        if (!file.exists() && file.mkdir()) {
            log.info("文件夹创建成功,创建位置:{}", JSONUtil.toJsonStr(path));
        }
    }

    /**
     * 输入路径判断文件夹是否存在 不存在则进行创建
     * 该方法支持逐级创建文件夹
     *
     * @param path
     */
    public static void noExistCreateDirs(String path) {
        File file = getFile(path);
        if (!file.exists() && file.mkdirs()) {
            log.info("文件夹逐级创建成功,创建位置:{}", JSONUtil.toJsonStr(path));
        }
    }

    /**
     * 输入路径判断文件是否存在 不存在则进行创建
     *
     * @param path
     */
    public static void noExistCreateFile(String path) {
        File file = getFile(path);
        try {
            if (!file.exists() && file.createNewFile()) {
                log.info("文件创建成功,创建位置:{}", JSONUtil.toJsonStr(path));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static File writeTempFile(String str, String prefix) {
        File tempFile = null;
        try {
            tempFile = File.createTempFile(prefix, ".txt");

            FileOutputStream fos = new FileOutputStream(tempFile, true);
            //true表示在文件末尾追加
            fos.write(str.getBytes());
            fos.close();
        } catch (IOException e) {
            log.error("writeTempFile IOException", e);
        }
        return tempFile;
    }

    /**
     * 判断文件夹存在
     * 获取文件夹里面所有的文件
     * 不递归获取
     *
     * @param path
     */
    public static List<File> existDirGetChildFiles(String path) {
        return getDirFiles(path, false);
    }

    /**
     * 判断文件夹存在
     * 获取文件夹里面所有的文件
     * recursion 为false 不递归获取 为true递归获取文件夹下的文件
     *
     * @param path
     * @param recursion
     * @return
     */
    public static List<File> existDirGetChildFiles(String path, boolean recursion) {
        return getDirFiles(path, recursion);
    }


    private static List<File> getDirFiles(String path, boolean recursion) {
        File dirFile = existRetFile(path);
        if (Objects.isNull(dirFile) || dirFile.isFile()) {
            return new ArrayList();
        }
        File[] childrenFiles = dirFile.listFiles();
        if (ArrayUtil.isEmpty(childrenFiles)) {
            return new ArrayList();
        }
        List<File> files = new ArrayList<>();
        for (File file : childrenFiles) {
            if (file.isFile()) {
                files.add(file);
            } else {
                if (!recursion) {
                    continue;
                } else {
                    List<File> fileList = getDirFiles(file.getPath(), recursion);
                    if (!CollectionUtils.isEmpty(fileList)) {
                        files.addAll(fileList);
                    }
                }
            }
        }
        return files;
    }

    /**
     * 根据path得到文件（File）
     *
     * @param path
     * @return
     */
    private static File getFile(String path) {
        File file = new File(path);
        return file;
    }

    public static void copyCreateFile(InputStream absolutePathStream, String nowPath) {
        copyCreateFile(absolutePathStream, nowPath, true);
    }

    /**
     * absolutePathStream 原始文件流
     * nowPath 待生成的文件位置
     * 此方法只支持 文本格式copy
     * 追加式写入
     *
     * @param absolutePathStream 流文件
     * @param nowPath
     */
    public static void copyCreateFile(InputStream absolutePathStream, String nowPath, boolean append) {
        BufferedReader input = null;
        BufferedWriter out = null;
        try {
            input = new BufferedReader(new InputStreamReader(absolutePathStream));
            File nowFile = getFile(nowPath);
            //追加式的写入，如果是覆盖式的，讲true去掉
            out = new BufferedWriter(new FileWriter(nowFile, append));
            String line = null;
            while ((line = input.readLine()) != null) {
                //写入
                out.write(line);
                //换行
                out.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                }
                if (input != null) {
                    input.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 批量删除文件
     *
     * @param filePaths
     */
    public static void deleteFilesByPathList(List<String> filePaths) {
        if (CollectionUtils.isEmpty(filePaths)) {
            return;
        }
        for (String filePath : filePaths) {
            File file = new File(filePath);
            file.delete();
        }
    }


    /**
     * 批量删除文件
     *
     * @param files
     */
    public static void deleteFiles(List<File> files) {
        if (CollectionUtils.isEmpty(files)) {
            return;
        }
        for (File file : files) {
            file.delete();
        }
    }

    /**
     * 转换文件大小
     */
    public static String formatFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        if (fileS == 0) {
            fileSizeString = "0.00B";
        } else {
            if (fileS < 1024) {
                fileSizeString = df.format((double) fileS) + "B";
            } else if (fileS < 1048576) {
                fileSizeString = df.format((double) fileS / 1024) + "KB";
            } else if (fileS < 1073741824) {
                fileSizeString = df.format((double) fileS / 1048576) + "MB";
            } else {
                fileSizeString = df.format((double) fileS / 1073741824) + "GB";
            }
        }

        return fileSizeString;
    }


    /**
     * 计算文件的MD5值
     *
     * @param file
     * @return
     */
    public static String getFileMD5(File file) {
        if (!file.isFile()) {
            return null;
        }
        MessageDigest digest = null;
        FileInputStream in = null;
        byte[] buffer = new byte[8192];
        int len;
        try {
            digest = MessageDigest.getInstance("MD5");
            in = new FileInputStream(file);
            while ((len = in.read(buffer)) != -1) {
                digest.update(buffer, 0, len);
            }
            return new BigInteger(1, digest.digest()).toString(16);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    public static void downloadFile(String filePath, String url, String packageName, String fileMD5) {
        log.info("网管上传的文件为-{}", packageName);
        File f = new File(filePath);
        if (!f.exists()) {
            f.mkdirs();
        }
        String fullPath = filePath + "/" + packageName;
        File file = new File(fullPath);
        if (!(file.exists() && fileMD5.equals(getFileMD5(file)))) {
            //从网管下载
            downloadFromNetshark(url, fullPath);
            log.info("mpu下载文件成功-{}", fullPath);
        }
    }


    public static void downloadFromNetshark(String url, String fullPath) {
        InputStream inStream = null;
        FileOutputStream fs = null;
        try {
            // 构造URL
            URL u = new URL(url);
            // 打开连接
            URLConnection conn = u.openConnection();
            int fileSize = conn.getContentLength();
            // 输入流
            inStream = conn.getInputStream();
            //1K的数据缓冲
            byte[] buffer = new byte[1024];
            // 读取到的数据长度
            int length, curSize = 0, readNum = 0;

            fs = new FileOutputStream(fullPath, false); //false：覆盖文件,true:在原有文件后追加
            //开始读取
            fileSize /= 100;  //百分比
            while ((length = inStream.read(buffer)) != -1) {
                fs.write(buffer, 0, length);
                ++readNum;
                curSize += length;
                if (readNum % 100 == 0) {
                    log.info("文件下载进度：======== {}, {}%", curSize, curSize / fileSize);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭所有连接
            if (null != fs) {
                try {
                    fs.flush();
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != inStream) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
